import lombok.Data;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;

/**
 * <p>
 * 区块
 * </p>
 *
 * @author KANLEI
 * @email freefree.me@qq.com
 * @create 2020-10-28
 */
@Slf4j
@Data
@ToString
public class Block {

    public String hash;

    public String previousHash;

    public String merkleRoot;

    public ArrayList<Transaction> transactions = new ArrayList<>();

    private Long timestamp;
    // 挖矿次数
    private int nonce;

    public Block(String previousHash) {
        this.previousHash = previousHash;
        this.timestamp = System.currentTimeMillis();
        this.hash = calculate();
    }

    /**
     * 计算hash
     * previousHash + timestamp + data -> current-block hash
     *
     * @return
     */
    public String calculate() {
        return StringUtils.applySHA256(
                previousHash + timestamp + nonce + merkleRoot
        );
    }

    /**
     * 挖矿
     *
     * @param difficult 挖矿难度
     */
    public void mineBlock(int difficult) {

        String target = new String(new char[difficult]).replace("\0", "0");
        while (!target.equalsIgnoreCase(hash.substring(0, difficult))) {
            nonce++;
            hash = calculate();
        }
        log.info("Mined Block!!! " + hash);
    }
    // add transactions to block
    public boolean addTransaction(Transaction transaction) {
        if (transaction == null) return false;
        if (!(previousHash.equalsIgnoreCase("0"))) {
            if (!transaction.processTransaction()) {
                log.error("The transaction is failure, Discarded.");
                return false;
            }
        }
        transactions.add(transaction);
        log.info("The Block add the transaction successful.");
        return true;
    }
}
